﻿#include "box_channel.hh"
#include "box_network.hh"

#include "knet/knet.h"

#include "../config/box_config.hh"

#include "../util/box_debug.hh"

namespace kratos {
namespace service {

BoxChannel::BoxChannel(std::uint64_t id, BoxNetwork *network,
                       const std::string &name) {

  channel_id_ = id;
  network_ = network;
  channel_name_ = name;

  const auto &config_ref = network->get_config();
  rb_ = ringbuffer_create(config_ref.get_box_channel_recv_buffer_len());

  box_assert(network, !rb_);
}

BoxChannel::~BoxChannel() {
  if (rb_) {
    ringbuffer_destroy(rb_);
  }
  channel_id_ = 0;
  rb_ = nullptr;
  network_ = nullptr;
}

int BoxChannel::send(const char *data, int size) {
  if (is_close_) {
    return 0;
  }
  if (!data || !size) {
    return 0;
  }
  return network_->enqueue_send_request(channel_id_, data, size);
}

int BoxChannel::peek(char *data, int size) {
  if (is_close_) {
    return 0;
  }
  if (!data || !size) {
    return 0;
  }
  return ringbuffer_copy(rb_, data, size);
}

int BoxChannel::recv(char *data, int size) {
  if (is_close_) {
    return 0;
  }
  if (!data || !size) {
    return 0;
  }
  return ringbuffer_read(rb_, data, size);
}

int BoxChannel::skip(int size) {
  if (is_close_) {
    return 0;
  }
  if (!size) {
    return 0;
  }
  if (error_ok == ringbuffer_eat(rb_, size)) {
    return size;
  }
  return 0;
}

int BoxChannel::size() {
  if (is_close_) {
    return 0;
  }
  return ringbuffer_available(rb_);
}

bool BoxChannel::isClose() { return is_close_; }

void BoxChannel::close() {
  if (is_close_) {
    return;
  }
  is_close_ = true;
  network_->close_channel(channel_id_);
}

const rpc::Address& BoxChannel::getLocalAddress() { return local_addr_; }

const rpc::Address& BoxChannel::getPeerAddress() { return peer_addr_; }

std::uint64_t BoxChannel::get_id() const noexcept { return channel_id_; }

int BoxChannel::write_buffer(const char *data, int size) noexcept {
  if (!data || !size) {
    return 0;
  }
  if (is_close_) {
    // 防止外部处理不需要处理的错误
    return size;
  }
  return ringbuffer_write(rb_, data, size);
}

void BoxChannel::set_close_flag() noexcept { is_close_ = true; }

const std::string &BoxChannel::get_channel_name() const noexcept {
  return channel_name_;
}

auto BoxChannel::set_channel_name(const std::string &name) noexcept -> void {
  channel_name_ = name;
}

auto BoxChannel::set_coro_listener_name(const std::string &name) noexcept
    -> void {
  coro_listener_name_ = name;
}

auto BoxChannel::get_coro_listener_name() const noexcept
    -> const std::string & {
  return coro_listener_name_;
}

auto BoxChannel::set_user_data(std::uint64_t user_data) noexcept -> void {
  user_data_ = user_data;
}

auto BoxChannel::get_user_data() const noexcept -> std::uint64_t {
  return user_data_;
}

auto BoxChannel::set_address(const rpc::Address &local,
                             const rpc::Address &peer) -> void {
  local_addr_ = local;
  peer_addr_ = peer;
}

} // namespace service
} // namespace kratos
